package indexer;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HtmlDocument extends Document {
	private String _htmlCode = "";
	// / <summary>MimeType so we know whether to try and parse the contents, eg.
	// "text/html", "text/plain", etc</summary>
	private final String _MimeType = "";

	// #region Constructors

	public HtmlDocument(URI location) {
		super(location);
	}

	public HtmlDocument(URI location, String mimeType) {
		super(location, mimeType);
	}

	// #region Parsing

	public @Override
	void Parse() {
		ParseImages();
		ParseLinks();
	}

	private void ParseImages() {
		Pattern imgPattern = Pattern.compile("<img[^>]*>",
				Pattern.CASE_INSENSITIVE);// @"<img([^>]*)\ssrc=(['""])(?:[^\2\/]*\/)*([^\2]+)\2";
		// @"<img[^>]*src *=*[""\']?([^""\']*)";////
		Pattern imgAttrPatter = Pattern
				.compile(
						"(?<name>\b\\w+\b)\\s*=\\s*(\"(?<value>[^\"]*)\"|'(?<value>[^']*)'|(?<value>[^\"'<> \\s]+)\\s*)+",
						Pattern.CASE_INSENSITIVE);

		Matcher imgMatcher = imgPattern.matcher(_htmlCode);
		while (imgMatcher.find()) {
			ImageObj img = new ImageObj(_Uri);

			Matcher imgAttrMatcher = imgAttrPatter.matcher(imgMatcher.group());
			while (imgAttrMatcher.find()) {
				switch (imgAttrMatcher.Groups[1].ToString().ToLower()) {
				case "src":
					img.setSrc = imgAttrMatcher.Groups[2].ToString();// new
																		// Uri(this.Uri,
					// match.Value
					break;
				case "alt":
					img.setAlt = imgAttrMatcher.Groups[2].ToString();
					break;
				case "class":
					img.setClassStr = imgAttrMatcher.Groups[2].ToString();
					break;
				case "id":
					img.setIdStr = imgAttrMatcher.Groups[2].ToString();
					break;
				case "longdesc":
					img.setLongDesc = imgAttrMatcher.Groups[2].ToString();
					break;
				case "title":
					img.setTitle = imgAttrMatcher.Groups[2].ToString();
					break;
				default:
					break;
				}
			}

			// if(local TODO
			img.DownloadImage();
		}
	}// Parse

	private void ParseLinks()
    {
        String link = "";

        // Looks for the src attribute of:
        // <A> anchor tags
        // <AREA> imagemap links
        // <FRAME> frameset links
        // <IFRAME> floating frames
        foreach (Match match in Regex.Matches(_htmlCode, "(?<anchor><\\s*(a|area|frame|iframe)\\s*(?:(?:\b\\w+\b\\s*(?:=\\s*(?:\"[^\"]*\"|'[^']*'|[^\"'<> ]+)\\s*)?)*)?\\s*>)", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
        {
            // Parse ALL attributes from within tags... IMPORTANT when they're out of order!!
            // in addition to the 'href' attribute, there might also be 'alt', 'class', 'style', 'area', etc...
            // there might also be 'spaces' between the attributes and they may be ", ', or unquoted
            link = "";

            foreach (Match submatch in new Regex.Matches(match.Value.ToString(), "(?<name>\b\\w+\b)\\s*=\\s*(\"(?<value>[^\"]*)\"|'(?<value>[^']*)'|(?<value>[^\"'<> \\s]+)\\s*)+", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
            {
                // we're only interested in the href attribute (although in future maybe index the 'alt'/'title'?)
                if ("href" == submatch.Groups[1].ToString().ToLower())
                {
                    link = submatch.Groups[2].ToString();

                    if (link != "#")
                    {
                        break; // break if this isn't just a placeholder href="#", which implies maybe an onclick attribute exists
                    }
                }else                if ("onclick" == submatch.Groups[1].ToString().ToLower())
                {
                    String jscript = submatch.Groups[2].ToString();
                    // some code here to extract a filename/link to follow from the onclick="_____"
                    // say it was onclick="window.location='top.htm'"
                    int firstApos = jscript.IndexOf("'");
                    int secondApos = jscript.IndexOf("'", firstApos + 1);
                    if (secondApos > firstApos)
                    {
                        link = jscript.Substring(firstApos + 1, secondApos - firstApos - 1);
                        break;  // break if we found something, ignoring any later href="" which may exist _after_ the onclick in the <a> element
                    }
                }
            }

            AddLinkToCollection(link);
        } // foreach
    }// Parse Links

	// / <summary>
	// / Checks link and adds it to external/local links collection
	// / </summary>
	// / <param name="link"></param>
	private void AddLinkToCollection(String link) {
		// strip off internal links, so we don't index same page over again
		if (link.contains("#")) {
			link = link.substring(0, link.indexOf("#"));
		}

		// !!!!!!!!!!!!!
		// if (link.Contains("?"))//!!!!!!!!!!!!!
		// {
		// link = link.Substring(0, link.IndexOf("?"));
		// }

		link = link.replace('\\', '/');

		if (!Document.IsAWebPage(link)) {
			return;
		}

		if (link.length() > 1
				&& !link.startsWith("/")
				&& (link.startsWith(Common.HTTP) || link.startsWith("https://"))) {
			try {
				URI address = new URI(link);
				String authority = address.getAuthority().replace(
						Common.MatchWwwDigitDotPattern, "");

				if (authority == _Uri.getAuthority()) {
					if (!_localLinks.Contains(address.PathAndQuery)) {
						_localLinks.Add(address.PathAndQuery); // gets only the
																// relative link
					}
				}
			} catch (Exception e) {
				// "Malformed URL: " + link)));
			}
		} else if (link.startsWith("?")) {
			if (!_localLinks.contains(_Uri.AbsolutePath + link)) {
				// it's possible to have /?query which sends the querystring to
				// the 'default' page in a directory
				_localLinks.Add(_Uri.AbsolutePath + link);
			}
		} else if (!_localLinks.contains(link)) {
			_localLinks.add(link);
		}
	}

	// #endregion parsing
	@Override
	public boolean GetResponse(HttpURLConnection connection) {
		BufferedReader respStream = null;
		StringBuilder sb = new StringBuilder();

		try {
			int encodingStart = -1;
			try {
				String contentType = connection.getContentType();
				encodingStart = contentType.indexOf("charset=");

				if (encodingStart != -1) {
					String encoding = contentType.substring(encodingStart + 8);
					respStream = new BufferedReader(new InputStreamReader(
							connection.getInputStream(), encoding));
				} else {
					respStream = new BufferedReader(new InputStreamReader(
							connection.getInputStream(), "UTF-8"));
				}

				connection.connect();

				if (!super.AddURLtoGlobalVisited(connection.getURL().toURI())) {
					return false;
				}

				String line;
				while ((line = respStream.readLine()) != null) {
					sb.append(line + File.separator);
				}

				_htmlCode = sb.toString();
			} catch (Exception e) {
				System.err.println("Couldn't get encoding!");
			}
		} finally {
			if (respStream != null) {
				try {
					respStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return true; // success
	}// GetResponse
}
